﻿using System;
using Firefly.Framework.ContentManagement;
using Microsoft.Xna.Framework;
using Microsoft.Xna.Framework.Content;
using Microsoft.Xna.Framework.Graphics;

namespace Firefly.Framework.Windows
{
    public class Font : IPipelineSerializeable, IHasContent, IDisposableEx
    {
        public string AssetName { get; set; }
        public SpriteFont SpriteFont { get; private set; }

        public Vector2 MeasureString(int size, string text)
        {
            if (text == string.Empty)
            {
                return new Vector2(0, 0);
            }

            Vector2 result = SpriteFont.MeasureString(text) * Scale(size, text);
            result.X = (float)Math.Ceiling(result.X);
            result.Y = (float)Math.Ceiling(result.Y);
            return result;
        }

        public float Scale(int size, string text)
        {
            string toMeasure = (text.IndexOf("\n") == -1) ? text : text.Substring(0, text.IndexOf("\n"));
            Vector2 nativeSize = SpriteFont.MeasureString(toMeasure);
            return size / nativeSize.Y;
        }

        public float CursorPosition(int pos, string text, int size)
        {
            return (float)Math.Ceiling(MeasureString(size, text.Substring(0, pos)).X);
        }

        public int CursorPosition(string text, Point position, Rectangle rectangle, int size)
        {
            string stringPart = text;

            if (position.X >= rectangle.Right)
            {
                return text.Length - 1;
            }

            if (position.X < rectangle.X)
            {
                return -1;
            }

            int clickLength = position.X - rectangle.X;
            
            if (clickLength < 0) 
            { 
                return -1; 
            }

            Vector2 nextLength = Vector2.Zero;

            if (!string.IsNullOrEmpty(stringPart))
            {
                MeasureString(size, stringPart.Substring(0, stringPart.Length - 1));
            }
            else
            {
                return 0;
            }

            Vector2 length = MeasureString(size, stringPart);

            while ((nextLength.X > (clickLength)) && (stringPart.Length > 1))
            {
                stringPart = stringPart.Substring(0, stringPart.Length - 1);
                nextLength = MeasureString(size, stringPart.Substring(0, stringPart.Length - 1));
                length = MeasureString(size, stringPart);
            }

            float lengthDifference = Math.Abs(clickLength - length.X);
            float nextDifference = Math.Abs(clickLength - nextLength.X);
            float result = (lengthDifference < nextDifference) ? stringPart.Length : stringPart.Length - 1;
            return (int)Math.Ceiling(result);
        }

        public string Trim(string text, Rectangle rect, int size)
        {
            string result = text;
            Vector2 stringSize = MeasureString(size, result);
            Vector2 interiorSize = new Vector2(rect.Width, rect.Height);

            while (stringSize.X > interiorSize.X)
            {
                result = result.Substring(0, result.Length - 1);
                stringSize = MeasureString(size, result);
            }

            return result;
        }

        public void Draw(string text, Vector2 position, int size, Color color)
        {
            if (text.Trim() == string.Empty)
            {
                return;
            }

            float scale = Scale(size, text);
            WindowsService.Instance.SpriteBatch.DrawString(SpriteFont, text, position, color, 0, new Vector2(0, 0), scale, SpriteEffects.None, 0);
        }

        public void Draw(string text, Rectangle rect, int size, Color color)
        {
            if (text.Trim() == string.Empty)
            {
                return;
            }

            string shorttext;
            shorttext = Trim(text, rect, size);
            float scale = Scale(size, shorttext);
            WindowsService.Instance.SpriteBatch.DrawString(SpriteFont, shorttext, new Vector2(rect.X, rect.Y), color, 0, Vector2.Zero, scale, SpriteEffects.None, 0);
        }

        public void Draw(int pos, string text, Rectangle rect, Color color, int size)
        {
            Vector2 vectorPosition = MeasureString(size, text.Substring(0, pos));
            WindowsService.Instance.DrawRectangle(new Rectangle(rect.X + (int)(vectorPosition.X), rect.Y, 1, size), color);
        }

        #region IPipelineSerializeable Members

        public void DeserializeContent(ContentReader input)
        {
            AssetName = input.ReadString();
            LoadContent();
        }

        #endregion

        #region IHasContent Members

        public void LoadContent()
        {

            SpriteFont = ContentService.Instance.Load<SpriteFont>(WindowsService.Instance.ThemePath + AssetName);
        }

        public void UnloadContent()
        {

            ContentService.Instance.Release(WindowsService.Instance.ThemePath + AssetName);
        }

        #endregion

        #region IDisposableEx Members

        public bool Disposed { get; private set; }

        #endregion

        #region IDisposable Members

        public void Dispose()
        {
            Dispose(true);
            GC.SuppressFinalize(this);
        }

        private void Dispose(bool disposing)
        {
            if (!Disposed)
            {
                if (disposing)
                {
                    UnloadContent();
                }

                Disposed = true;
            }
        }

        ~Font()
        {
            Dispose(false);
        }

        #endregion
    }
}
